/**
 * @Desc decorator函数
 * @Stage 完成
 */
import Vue, { PropOptions, WatchOptions } from "vue";

// 类装饰器
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

// 属性装饰器
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;

// 方法装饰器
declare type MethodDecorator = <T>(
  target: Object,
  propertyKey: string | symbol,
  descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void;

// 参数装饰器
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;

// done 已完成
/**
 * @Mehotd Function Decorator
 * @Desc 去抖动,延迟delayTime执行
 * @Params delayTime: number|string ,{default:300}
 * @Returns：Function
 * @Author codeXgea/lex
 * @LastTime 2019/12/14
 * */
export function Debounce(delayTime?: number | string): Function {
  const delayCounter = delayTime || 300;
  return function(target: object, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
    let timer: any;
    const oldValue = descriptor.value;
    return Object.assign(descriptor, {
      value: function() {
        let ctx: any = this;
        let args: any = arguments;
        timer && clearTimeout(timer);
        timer = setTimeout(() => {
          timer = null;
          oldValue.apply(ctx, [...args]);
        }, Number(delayCounter));
      },
    });
  };
}

/**
 * @Mehotd Function Decorator
 * @Desc 接口请求装饰器，装饰一个async Function
 * @Params  {
 *            preString:string, // 成功或者失败的前置信息
 *            loadingName?:string // loading变量名称，若没有则为'boolLoading'
 *            }
 * @Returns：Promise
 * @Author codeXgea/lex
 * @LastTime 2019/12/22
 * */
export function Waiting(args: string | waitingOption): Function {
  let loadingName: string | undefined = "boolLoading";
  let preString: string | any;
  const action = {
    undefined: () => {
      throw new Error("Waiting Decorator needs preString:string | {preString:string,loadingName:boolean}");
    },
    object: () => {
      preString = (args as waitingOption).preString;
      loadingName = (args as waitingOption).loadingName ?? "boolLoading";
    },
    string: () => {
      preString = args;
      loadingName = "boolLoading";
    },
  };
  // @ts-ignore
  action[typeof args]();
  return function(target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
    const method = propertyDescriptor.value;
    return Object.assign(propertyDescriptor, {
      value: function() {
        // @ts-ignore,eslint  会报错
        let that = this as any;
        that.$set(that, loadingName, true);
        return method
          .apply(this, arguments)
          .then((res: any) => {
            console.log(res);
            that.$message.success(`${preString}成功`);
          })
          .catch(() => {
            that.$message.error(`${preString}失败`);
          })
          .finally(() => {
            that.$set(that, loadingName, false);
          });
      },
    });
  };
}

/**
 * @Mehotd Function Decorator
 * @Desc 不管成功还是失败，都会撤销loading，不带提示
 * @Params  {
 *            loadingName?:string // loading变量名称，若没有则为'boolLoading'
 *            }
 * @Returns：Promise
 * @Author codeXgea/lex
 * @LastTime 2020/1/14
 * */
export function Loading(loadingName?: string): Function {
  let loadingKeys = loadingName ? loadingName : "boolLoading";
  return function(target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
    const method = propertyDescriptor.value;
    return Object.assign(propertyDescriptor, {
      value: function() {
        // @ts-ignore,eslint  会报错
        let that: any = this;
        that.$set(that, loadingKeys, true);
        return method.apply(this, arguments).finally(() => {
          that.$set(that, loadingKeys, false);
        });
      },
    });
  };
}
